

#include "RtBase.h"
#include "RtConnectionInterface.h"
#include "RtConnectorWrapper.h"
#include "RtDetectionConnector.h"
#include "RtAcceptorTcp.h"
#include "RtAcceptorUdp.h"
#include "RtThreadInterface.h"
#include "RtThreadManager.h"
//#include "RtThreadReactor.h"
#include "RtConnectorThreadProxy.h"
#include "RtAcceptorThreadProxy.h"

#include "RtCnRlbTcp.h"
#include "RtCnPkg.h"
#include "RtCnPkgSender.h"
#include "RtCnLenPkg.h"
#include "RtCnRudp.h"
#include "RtConnRlbTcp.h"

CRtConnectionManager CRtConnectionManager::s_rtConnectionManagerSingleton;

CRtConnectionManager::CRtConnectionManager()
	/**: m_pThreadNetwork(NULL)**/
{
}

CRtConnectionManager::~CRtConnectionManager()
{
}

CRtConnectionManager* CRtConnectionManager::Instance()
{
/**
	if (!s_rtConnectionManagerSingleton.m_pThreadNetwork) {
		RtResult rv = s_rtConnectionManagerSingleton.SpawnNetworkThread_i();
		if (RT_FAILED(rv)) {
			RT_ERROR_TRACE("CRtConnectionManager::Instance, SpawnNetworkThread_i() failed!"
				" rv=" << rv);
			return NULL;
		}
	}
**/
	return &s_rtConnectionManagerSingleton;
}

void CRtConnectionManager::CleanupInstance()
{
	/**s_rtConnectionManagerSingleton.m_pThreadNetwork = NULL;**/
}

RtResult CRtConnectionManager::
CreateCnConnectionClient(CType &aType, IRtConnector *&aConClient)
{
	RtResult rv = RT_ERROR_FAILURE;

	//Decide Base Connection Type
	CType typeBaseConnection = (aType & CRtConnectionManager::CTYPE_TYPE_MASK);
	
	if (RT_BIT_CMP_MASK(aType, CTYPE_PACKAGE_TCP, CTYPE_PACKAGE_TCP) || RT_BIT_CMP_MASK(aType, CTYPE_PACKAGE_TCP_VIA_PROXY, CTYPE_PACKAGE_TCP_VIA_PROXY) ) 
	{
		CRtAutoPtr<IRtConnector> pTPConnector;
		rv = CreateConnectionClient_i(
			typeBaseConnection, 
			pTPConnector.ParaOut());

		if(RT_FAILED(rv))
			return rv;

		CRtAutoPtr<CRtConnRlbTcpConnector> pConnConnector = new CRtConnRlbTcpConnector(pTPConnector.ParaIn(), aType);
		if(pConnConnector.Get()) {
			rv = RT_OK;
			aConClient = pConnConnector.Get();
		}
		else {
			rv = RT_ERROR_OUT_OF_MEMORY;
			aConClient= NULL;
		}

		aType = CTYPE_PDU_RELIABLE;

		if (aConClient)
			aConClient->AddReference();
	}
	else if(RT_BIT_ENABLED(aType, CTYPE_PDU_LENGTH)) {

		RT_ASSERTE(typeBaseConnection != CRtConnectionManager::CTYPE_UDP);

		CRtAutoPtr<IRtConnector> pTPConnector;
		rv = CreateConnectionClient_i(
			typeBaseConnection, 
			pTPConnector.ParaOut());

		if(RT_FAILED(rv))
			return rv;
		
		CRtAutoPtr<CLenPkgConnConnector> pConnConnector(new CLenPkgConnConnector(pTPConnector.ParaIn(), aType) );

		if(pConnConnector.Get()) {
			rv = RT_OK;
			aConClient = pConnConnector.Get();
		}
		else {
			rv = RT_ERROR_OUT_OF_MEMORY;
			aConClient= NULL;
		}

		aType = CTYPE_PDU_LENGTH;

		if (aConClient)
			aConClient->AddReference();

//		RT_INFO_TRACE("CRtConnectionManager::CreateCnConnectionClient(), CTYPE_PDU_LENGTH, BaseType = " << ((typeBaseConnection == CTYPE_TCP) ? "TCP" : "UDP"));
	}
	else if (RT_BIT_CMP_MASK(aType, CTYPE_RUDP, CTYPE_RUDP))
	{
		CRtAutoPtr<IRtConnector> pTPConnector;
		rv = CreateConnectionClient_i(
			typeBaseConnection, 
			pTPConnector.ParaOut());

		if(RT_FAILED(rv))
			return rv;

		CRtAutoPtr<CRtRudpConnConnector> pConnConnector(new CRtRudpConnConnector(pTPConnector.ParaIn(), aType, TRUE) );

		if(pConnConnector.Get()) {
			rv = RT_OK;
			aConClient = pConnConnector.Get();
		}
		else {
			rv = RT_ERROR_OUT_OF_MEMORY;
			aConClient= NULL;
		}

		aType = CTYPE_RUDP;

		if (aConClient)
			aConClient->AddReference();

//		RT_INFO_TRACE("CRtConnectionManager::CreateCnConnectionClient(), CTYPE_RUDP");
	}
	
	return rv;
}

RtResult CRtConnectionManager::
CreateConnectionClient_i(CType aType, IRtConnector *&aConClient)
{
	RtResult rv = RT_ERROR_FAILURE;
	RT_ASSERTE(!aConClient);
	aConClient = NULL;

	CType typeConnection = aType;

	/////////////////////Connection Service Add Begin/////////////////////
	CRtAutoPtr<IRtConnector> pConConnector;
	if(RT_BIT_ENABLED(typeConnection, CTYPE_PDU_MASK) 
		|| RT_BIT_ENABLED(typeConnection, CTYPE_SEND_MASK)) {
		rv = CreateCnConnectionClient(typeConnection, pConConnector.ParaOut());
		if (RT_FAILED(rv)) {
			aConClient = NULL;
			return rv;
		}
	}
	/////////////////////Connection Service Add End//////////////////////
	
	switch(typeConnection) {
	case CTYPE_TCP: 
	case CTYPE_UDP:
	case CTYPE_SSL_DIRECT:
	case CTYPE_SSL_WITH_BROWER_PROXY:
	case CTYPE_SSL:
	case CTYPE_TCP_WITH_BROWER_PROXY:
	{
		std::auto_ptr<CRtConnectorWrapper> pCw(new CRtConnectorWrapper());
		if (pCw.get()) {
			rv = pCw->Init(typeConnection);
			if (RT_SUCCEEDED(rv))
				aConClient = pCw.release();
		}
		else {
			rv = RT_ERROR_OUT_OF_MEMORY;
			aConClient= NULL;
		}
		break;
	}

	case CTYPE_TCP_WITH_BROWER_PROXY | CTYPE_TCP:
	{
		std::auto_ptr<CRtDetectionConnector> pConClient(new CRtDetectionConnector());
		if (!pConClient.get()) {
			rv = RT_ERROR_OUT_OF_MEMORY;
			break;
		}

		//pConClient->SetTimeDelay(CRtTimeValue(10L));

		CRtInetAddr addrNull;
		CRtTimeValue tv(0, 0);
		rv = pConClient->AddConnection(CTYPE_TCP_WITH_BROWER_PROXY, addrNull,&tv);
		if (RT_SUCCEEDED(rv)) {
			rv = pConClient->AddConnection(CTYPE_TCP, addrNull,&tv);
			if (RT_SUCCEEDED(rv))
				aConClient = pConClient.release();
		}
		break;
	}

	/////////////////////Connection Service Add Begin/////////////////////
	case CTYPE_PDU_RELIABLE:
	case CTYPE_PDU_LENGTH:
	case CTYPE_RUDP:
	{
		aConClient = pConConnector.Get();
		break;
	}
	/////////////////////Connection Service Add End//////////////////////
	default:
		RT_ERROR_TRACE("CRtConnectionManager::CreateConnectionClient_i, wrong type=" << aType);
		rv = RT_ERROR_INVALID_ARG;
		aConClient= NULL;
		break;
	}

#ifdef RT_DEBUG
	if (RT_SUCCEEDED(rv))
		RT_ASSERTE(aConClient);
	else
		RT_ASSERTE(!aConClient);
#endif // RT_DEBUG

	if (aConClient)
		aConClient->AddReference();
	return rv;
}

RtResult CRtConnectionManager::
CreateCnConnectionServer(CType &aType, IRtAcceptor *&aAcceptor)
{
	RtResult rv = RT_ERROR_FAILURE;

	//Decide Base Connection Type
	CType typeBaseConnection = (aType & CRtConnectionManager::CTYPE_TYPE_MASK);
	
	if (RT_BIT_CMP_MASK(aType, CTYPE_PACKAGE_TCP, CTYPE_PACKAGE_TCP) ) 
	{
		CRtAutoPtr<IRtAcceptor> pTPAcceptor;
		rv = CreateConnectionServer(
			typeBaseConnection, 
			pTPAcceptor.ParaOut());

		if(RT_FAILED(rv))
			return rv;
		
		CRtAutoPtr<CRtConnRlbTcpAcceptorSink> pConnAcceptorSink(new CRtConnRlbTcpAcceptorSink);
		CRtAutoPtr<CRtConnRlbTcpAcceptor> pConnAcceptor(
			new CRtConnRlbTcpAcceptor(
			pTPAcceptor.ParaIn(), 
			pConnAcceptorSink.ParaIn(),
			aType) );

		aType = CTYPE_PDU_RELIABLE;
		
		if(pConnAcceptor.Get()) {
			rv = RT_OK;
			aAcceptor = pConnAcceptor.Get();
		}
		else {
			rv = RT_ERROR_OUT_OF_MEMORY;
			aAcceptor= NULL;
		}

		if (aAcceptor)
			aAcceptor->AddReference();
	}
	else if(RT_BIT_ENABLED(aType, CTYPE_PDU_LENGTH)) {

		RT_ASSERTE(typeBaseConnection != CRtConnectionManager::CTYPE_UDP);
		
		CRtAutoPtr<IRtAcceptor> pTPAcceptor;
		rv = CreateConnectionServer(
			typeBaseConnection, 
			pTPAcceptor.ParaOut());

		if(RT_FAILED(rv))
			return rv;
		
		CRtAutoPtr<CLenPkgConnAcceptorSink> pPkgSenderAcceptorSink(new CLenPkgConnAcceptorSink);
		CRtAutoPtr<CLenPkgConnAcceptor> pConnAcceptor(
			new CLenPkgConnAcceptor(
			pTPAcceptor.ParaIn(), 
			pPkgSenderAcceptorSink.ParaIn(), 
			aType) );
		
		aType = CTYPE_PDU_LENGTH;
		
		if(pConnAcceptor.Get()) {
			rv = RT_OK;
			aAcceptor = pConnAcceptor.Get();
		}
		else {
			rv = RT_ERROR_OUT_OF_MEMORY;
			aAcceptor= NULL;
		}

		if (aAcceptor)
			aAcceptor->AddReference();

//		RT_INFO_TRACE("CRtConnectionManager::CreateCnConnectionServer(), CTYPE_PDU_LENGTH, BaseType = " << ((typeBaseConnection == CTYPE_TCP) ? "TCP" : "UDP"));
	}
	else if (RT_BIT_CMP_MASK(aType, CTYPE_RUDP, CTYPE_RUDP))
	{
		CRtAutoPtr<IRtAcceptor> pTPAcceptor;
		rv = CreateConnectionServer_i(
			typeBaseConnection, 
			pTPAcceptor.ParaOut());

		if(RT_FAILED(rv))
			return rv;

		RT_INFO_TRACE("CRtConnectionManager::CreateCnConnectionServer, RUDP");
		((CRtAcceptorUdp*)pTPAcceptor.Get())->ListenForRudp();

		// Only server side have a choice not to send keep-alive. 
		// On client side, rudp always need send keep-alive.
		BOOL bNeedKeepAlive = FALSE;
		if(RT_BIT_ENABLED(aType, CTYPE_PDU_KEEPALIVE))
			bNeedKeepAlive = TRUE;
		
		CRtAutoPtr<CRtRudpConnAcceptorSink> pConnAcceptorSink(new CRtRudpConnAcceptorSink);
		CRtAutoPtr<CRtRudpConnAcceptor> pConnAcceptor(
			new CRtRudpConnAcceptor(
			pTPAcceptor.ParaIn(), 
			pConnAcceptorSink.ParaIn(), 
			aType,
			bNeedKeepAlive) );
		
		aType = CTYPE_RUDP;
		
		if(pConnAcceptor.Get()) {
			rv = RT_OK;
			aAcceptor = pConnAcceptor.Get();
		}
		else {
			rv = RT_ERROR_OUT_OF_MEMORY;
			aAcceptor= NULL;
		}

		if (aAcceptor)
			aAcceptor->AddReference();

//		RT_INFO_TRACE("CRtConnectionManager::CreateCnConnectionServer(), CTYPE_RUDP");
	}

	return rv;
}

RtResult CRtConnectionManager::
CreateConnectionServer_i(CType aType, IRtAcceptor *&aAcceptor)
{
	RtResult rv = RT_ERROR_FAILURE;
	RT_ASSERTE(!aAcceptor);
	aAcceptor = NULL;

	CType typeAcception = aType;
	
	/////////////////////Connection Service Add Begin/////////////////////
	CRtAutoPtr<IRtAcceptor> pConnAcceptor = NULL;
	if(RT_BIT_ENABLED(typeAcception, CTYPE_PDU_MASK) 
		|| RT_BIT_ENABLED(typeAcception, CTYPE_SEND_MASK)) {
		rv = CreateCnConnectionServer(typeAcception, pConnAcceptor.ParaOut());
		if (RT_FAILED(rv)) {
			aAcceptor = NULL;
			return rv;
		}
	}
	/////////////////////Connection Service Add End//////////////////////
	
	switch(typeAcception) {
	case CTYPE_TCP: 
		aAcceptor = new CRtAcceptorTcp();
		if (aAcceptor)
			rv = RT_OK;
		break;

	case CTYPE_UDP:
		aAcceptor = new CRtAcceptorUdp();
		if (aAcceptor)
			rv = RT_OK;
		break;
	/////////////////////Connection Service Add Begin/////////////////////
	case CTYPE_PDU_RELIABLE:
	case CTYPE_PDU_LENGTH:
	case CTYPE_RUDP:
	{
		aAcceptor = pConnAcceptor.Get();
		break;
	}
	/////////////////////Connection Service Add End//////////////////////
	default:
		RT_ERROR_TRACE("CRtConnectionManager::CreateConnectionServer, wrong type=" << aType);
		rv = RT_ERROR_INVALID_ARG;
		break;
	}

#ifdef RT_DEBUG
	if (RT_SUCCEEDED(rv))
		RT_ASSERTE(aAcceptor);
	else
		RT_ASSERTE(!aAcceptor);
#endif // RT_DEBUG

	if (aAcceptor)
		aAcceptor->AddReference();
	return rv;
}

RtResult CRtConnectionManager::
CreateDetectionConnectionClient(IRtDetectionConnector *&aConClient)
{
	RT_ASSERTE(!aConClient);
	RtResult rv = RT_OK;
	
	std::auto_ptr<CRtDetectionConnector> pCw(new CRtDetectionConnector());
	if (pCw.get()) {
			aConClient = pCw.release();
	}
	else {
		rv = RT_ERROR_OUT_OF_MEMORY;
		aConClient= NULL;
	}

	if(aConClient)
		aConClient->AddReference();

	return rv;
}

/**
RtResult CRtConnectionManager::SpawnNetworkThread_i()
{
	// we have to instance CRtThreadManager because it will invoke SpawnNetworkThread_i().
	CRtThreadManager *pInst = CRtThreadManager::Instance();
	if (m_pThreadNetwork)
		return RT_OK;

	CRtThreadManager::TModule tmodule = CRtThreadManager::GetNetworkThreadModule();
	if (tmodule == CRtThreadManager::TM_SINGLE_MAIN) {
		std::auto_ptr<CRtThreadDummy> pThreadReactor(new CRtThreadDummy());
		if (!pThreadReactor.get())
			return RT_ERROR_OUT_OF_MEMORY;

		RtResult rv = pThreadReactor->Init(
			pInst->GetThread(CRtThreadManager::TT_MAIN), CRtThreadManager::TT_NETWORK);
		if (RT_FAILED(rv))
			return rv;

		m_pThreadNetwork = pThreadReactor.release();
	}
	else {
		IRtReactor *pReactorNetwork = CRtThreadManager::CreateNetworkReactor();
		RtResult rv = pInst->CreateReactorThread(
			CRtThreadManager::TT_NETWORK, pReactorNetwork, m_pThreadNetwork);
		if (RT_FAILED(rv))
			return rv;
	}

	return RT_OK;
}
**/

RtResult CRtConnectionManager::
CreateConnectionClient(CType aType, IRtConnector *&aConClient)
{
	RT_ASSERTE(!aConClient);
	
	CRtThread *pNetwork = CRtThreadManager::Instance()->GetThread(CRtThreadManager::TT_NETWORK);
	if (CRtThreadManager::IsEqualCurrentThread(pNetwork->GetThreadId()) ) 
	{
		return CreateConnectionClient_i(aType, aConClient);
	}
	else {
		CRtConnectorThreadProxy *pConProxy = 
			new CRtConnectorThreadProxy(aType, pNetwork);
		if (!pConProxy)
			return RT_ERROR_OUT_OF_MEMORY;

		aConClient = pConProxy;
		aConClient->AddReference();
		return RT_OK;
	}
}

RtResult CRtConnectionManager::
CreateConnectionServer(CType aType, IRtAcceptor *&aAcceptor)
{
	RT_ASSERTE(!aAcceptor);

	CRtThread *pNetwork = CRtThreadManager::Instance()->GetThread(CRtThreadManager::TT_NETWORK);
	if (CRtThreadManager::IsEqualCurrentThread(pNetwork->GetThreadId()) ) 
	{
		return CreateConnectionServer_i(aType, aAcceptor);
	}
	else
	{
		CRtAcceptorThreadProxy *pAcceptorProxy = 
			new CRtAcceptorThreadProxy(aType, pNetwork);
		if (!pAcceptorProxy)
			return RT_ERROR_OUT_OF_MEMORY;

		aAcceptor = pAcceptorProxy;
		aAcceptor->AddReference();
		return RT_OK;
	}
}

